package com.deer.wms.ware.task.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.deer.wms.base.system.model.BillOutBO;
import com.deer.wms.base.system.model.BillOutDetailBO;
import com.deer.wms.base.system.model.Item.ItemInfo;
import com.deer.wms.base.system.service.CellInfoService;
import com.deer.wms.base.system.service.ItemInfoService;
import com.deer.wms.inventory.model.Inventory.Inventory;
import com.deer.wms.inventory.service.InventoryService;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.project.root.service.SuperServiceImpl;
import com.deer.wms.project.root.util.DateUtils;
import com.deer.wms.system.manage.model.ware.WareInfo;
import com.deer.wms.system.manage.service.CodeRuleService;
import com.deer.wms.system.manage.service.CrmDeptAreaService;
import com.deer.wms.system.manage.service.WareInfoService;
import com.deer.wms.ware.task.constant.WareTaskConstant;
import com.deer.wms.ware.task.dao.SoDetailMapper;
import com.deer.wms.ware.task.model.Return.SoLogItemDto;
import com.deer.wms.ware.task.model.SO.*;
import com.deer.wms.ware.task.model.SO.contrast.ContrastVo;
import com.deer.wms.ware.task.model.SO.vo.SoDetailVo;
import com.deer.wms.ware.task.model.Wave.WaveDetail;
import com.deer.wms.ware.task.model.pickTask.PickTask;
import com.deer.wms.ware.task.model.pickTask.PickTaskCriteria;
import com.deer.wms.ware.task.model.pickTask.PickTaskDto;
import com.deer.wms.ware.task.service.PickTaskService;
import com.deer.wms.ware.task.service.PushErpService;
import com.deer.wms.ware.task.service.SoDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.deer.wms.project.root.util.CollectionUtils.convertMap;

/**
 * Created by guo on 2020/02/02.
 */
@Service
@Transactional
public class SoDetailServiceImpl extends SuperServiceImpl<SoDetailMapper, SoDetail> implements SoDetailService {

    @Autowired
    private SoDetailMapper soDetailMapper;
    @Autowired
    private SoMasterServiceImpl soMasterService;
    @Autowired
    private PickTaskService pickTaskService;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private SoMasterServiceImpl soMasterServiceImpl;
    @Autowired
    private ItemInfoService itemInfoService;
    @Autowired
    private PushErpService pushErpService;
    @Autowired
    private WareInfoService wareInfoService;
    @Autowired
    private WaveDetailServiceImpl waveDetailService;

    @Autowired
    private CodeRuleService codeRuleService;

    @Override
    public List<SoDetailDto> findList(SoDetailCriteria criteria) {
        return soDetailMapper.findList(criteria);
    }

    @Override
    public List<SoDetailDto> findBaoKuanByItemCode(String itemCode, Integer wareId, Integer orgId) {
        return soDetailMapper.findBaoKuanByItemCode(itemCode, wareId, orgId);
    }

    @Override
    public List<SoDetail> findByBillNo(String billNo) {
        return list(new QueryWrapper<SoDetail>().in("bill_no", billNo));
//        SoDetailVo soDetailVo = new SoDetailVo();
//        return soDetailMapper.findByBillNo(billNo);
    }

    @Override
    public List<SoDetail> syncCurrentData(List<SoMaster> soMasters) {
        for (SoMaster soMaster : soMasters) {
            System.out.println(soMaster.getBillNo());
        }
        if (ObjectUtil.isEmpty(soMasters)) {
            return null;
        }
        //老单据
        Set<String> oldBillNos = soMasters.stream().map(SoMaster::getBillNo).collect(Collectors.toSet());
        List<Integer> collect = soMasters.stream().map(SoMaster::getBeforeNum).collect(Collectors.toList());
        Map<String, Object> map = new HashMap<>();
        map.put("billIds", collect);
        map.put("billTypeId", soMasters.iterator().next().getBillType());
        map.put("includeClosed", true);
        List<BillOutBO> po = pushErpService.OutSourceBill(map);
        if (ObjectUtil.isEmpty(po)) {
            return null;
        }
        Set<String> newBillSet = po.stream().map(item -> item.getBillNo()).collect(Collectors.toSet());




        List<SoDetail> soDetailList = new ArrayList<>();
        List<BillOutDetailBO> billOutDetailBOS = new ArrayList<>();


        //Step2.表头字段遍历到表体中
        po.stream().map(item -> {
            item.setDetails(soMasterService.insertBillNo(item));
            billOutDetailBOS.addAll(item.getDetails());
            return item;
        }).collect(Collectors.toList());

//        List<String> billNos = po.stream().map(item -> item.getBillNo()).collect(Collectors.toList());
        Map<String, SoMaster> soMasterMap = convertMap(soMasters, SoMaster::getBillNo);

        for (BillOutBO billOutBO : po) {
            String billNo = billOutBO.getBillNo();
            SoMaster soMaster = soMasterMap.get(billNo);
            if (soMaster.getSoType() == 28) {
                soMaster.setDeptId(641821);
                soMaster.setDeptName("配网车间");
            } else {
                soMaster.setDeptId(billOutBO.getDeptId());
                soMaster.setDeptName(billOutBO.getDeptName());
            }

        }

        soMasterService.updateBatchById(soMasters);
        List<SoDetail> newDetail = new ArrayList<>();

        //Step6.获取所有物料
        Set<String> itemNumbers = billOutDetailBOS.stream().map(BillOutDetailBO::getItemNumber).collect(Collectors.toSet());
        if (ObjectUtil.isEmpty(itemNumbers)) {
            throw new ServiceException(CommonCode.BATCH_TACTIC_ERROR, "该单据已拆分新单据，不可同步拉取");
        }
        //获取所有物料
        List<ItemInfo> itemInfoList = itemInfoService.list(new QueryWrapper<ItemInfo>().in("item_code", itemNumbers));
        Map<String, List<BillOutDetailBO>> detailMap = billOutDetailBOS.stream().collect(Collectors.groupingBy(BillOutDetailBO::getBillNo));
        //Strep7.红蓝字对冲,同一单号,不同的类型 入库出库数量对冲
        List<BillOutDetailBO> merge = soMasterService.merge(detailMap);
//        List<BillOutDetailBO> merge = billOutDetailBOS.stream().filter(item -> item.getTargetBillROB()).collect(Collectors.toList());
        Map<String, ItemInfo> itemInfoMap = convertMap(itemInfoList, ItemInfo::getItemCode);
        List<String> notCategory = Arrays.asList("标准件", "标准件-MRP物料", "辅料-MRP物料", "辅料");
        for (BillOutDetailBO billOutDetailBO : merge) {
            if (billOutDetailBO.getItemNumber().equals("08.10.0033")) {
                System.out.println("1111");
            }
            ItemInfo itemInfo = itemInfoMap.get(billOutDetailBO.getItemNumber());
            String feedCateGory = Optional.ofNullable(itemInfo).map(item -> item.getFeedCategory()).orElse("");
            if (notCategory.contains(feedCateGory) && billOutDetailBO.getTargetBillTypeId() == 24) {
                continue;
            }
            SoDetail soDetail = new SoDetail();
            soDetail.setBillNo(billOutDetailBO.getBillNo());
            soDetail.setErpBillId(billOutDetailBO.getSourceBillId());
            soDetail.setBomSplit(billOutDetailBO.getRowIndex());//行号
            soDetail.setAllotPackDetailId(billOutDetailBO.getItemId());//物料ID
            soDetail.setItemCode(billOutDetailBO.getItemNumber());//物料编码
            soDetail.setItemName(billOutDetailBO.getItemName());//物料名称
            soDetail.setSpec(billOutDetailBO.getItemModel());//规格型号
            soDetail.setPickPackDetailId(billOutDetailBO.getAuxPropClassId());//辅助属性类别ID
            soDetail.setDeliveryPackDetailId(billOutDetailBO.getAuxPropId());//辅助属性ID
            soDetail.setModel(billOutDetailBO.getAuxPropName());//辅助属性
            soDetail.setPackDescribe(billOutDetailBO.getBatchManager() == null || billOutDetailBO.getBatchManager() == false ? "0" : "1");
            soDetail.setPackDetailId(billOutDetailBO.getUnitId());//基本单位ID
            soDetail.setSoUdfDs2(billOutDetailBO.getUnitName());//单位
            soDetail.setOrderQuantity(billOutDetailBO.getOriginQty());//原始数量  变更数量
            soDetail.setPickQuantity(billOutDetailBO.getQcQty());
            soDetail.setStockId(billOutDetailBO.getStockId());
            soDetail.setAllottedQuantity(billOutDetailBO.getOriginQty() - billOutDetailBO.getQty());
            soDetail.setPickQuantity(billOutDetailBO.getOriginQty() - billOutDetailBO.getQty());
            soDetail.setDeliveryQuantity(billOutDetailBO.getOriginQty() - billOutDetailBO.getQty());
            soDetail.setMergeNo(billOutDetailBO.getAgreementNo());
            soDetail.setSoUdfDs3(billOutDetailBO.getMtoNo());//计划跟踪号
            soDetail.setDetailNo(billOutDetailBO.getBillNo()+"-"+billOutDetailBO.getRowIndex());
            soDetail.setMemo(billOutDetailBO.getRemark());//备注
            soDetail.setPickPackDescribe(billOutDetailBO.getTargetBillTypeId().toString());//目标单据类型ID
            soDetail.setRob(billOutDetailBO.getTargetBillROB());
            if (soDetail.getOrderQuantity() < 0) {
                continue;
//                soDetail.setOrderQuantity(0 - soDetail.getOrderQuantity());
            }
            soDetail.setTransRatio(1.00);

            soDetailList.add(soDetail);


        }
        return soDetailList;
    }

    public void saveSo(List<SoDetail> newDetail, List<BillOutBO> po) {
        List<SoMaster> soMasters = new ArrayList<>();
        Set<String> collect = newDetail.stream().map(SoDetail::getBillNo).collect(Collectors.toSet());
        Set<SoDetail> addDetail = new HashSet<>();
        //Step0.准备数据
        Integer wareId = 285;
        List<WareInfo> wareInfoList = wareInfoService.list();
        Map<Integer, WareInfo> wareInfoMap = wareInfoList.stream().collect(Collectors.toMap(WareInfo::getWareId, wareInfo -> wareInfo, (oldValue, newValue) -> newValue));
        Map<String, SoDetail> detailMap = newDetail.stream().collect(Collectors.toMap(SoDetail::getBillNo, detail -> detail, (oldValue, newValue) -> newValue));

        for (BillOutBO billOutBO : po) {
            if (!collect.contains(billOutBO.getBillNo())) {
                continue;
            }
            SoMaster soMaster = new SoMaster();
            soMaster.setCreateTime(DateUtils.getNowDateTimeString());
            soMaster.setOrganizationId(86);//货主id
            soMaster.setWareId(wareId);//仓库id
            soMaster.setWareCode(wareInfoMap.get(wareId).getWareCode());
            soMaster.setWareName(wareInfoMap.get(wareId).getWareName());
            soMaster.setSupplierId(billOutBO.getSupplierId());//供应商id
            soMaster.setSupplierName(billOutBO.getSupplierName()); // 供应商名称
            soMaster.setOrderBillNo(codeRuleService.generateCodeByRedis("OUT")); //订单号
            soMaster.setBeforeNum(billOutBO.getId());
            soMaster.setSoType(detailMap.get(billOutBO.getBillNo()).getPackDetailId()); ///单据类型id
            soMaster.setBillType(billOutBO.getBillTypeId()); //单据类型id
            soMaster.setSoTypeName(billOutBO.getBillTypeName());//单据类型名称
            soMaster.setTradeNo(billOutBO.getAgreementNo());  //履约号
            soMaster.setBillNo(billOutBO.getBillNo());//单据编号
            soMaster.setShipCode(billOutBO.getBillDate());//单据日期
            soMaster.setCarrierId(billOutBO.getBillStatus());//工业单据状态
            soMaster.setIsClose(billOutBO.getBillClosed() == null || billOutBO.getBillClosed() == false ? 0 : 1);//关闭状态
            soMaster.setOrganizationId(-1);
            soMaster.setOrganizationName("自有");
            soMaster.setOrganizationCode("SYS_MINE");
            soMaster.setOrderBillId(billOutBO.getOrderBillId());
            soMaster.setDeptId(billOutBO.getDeptId());//部门ID
            soMaster.setDeptName(billOutBO.getDeptName());//部门名称
            soMaster.setMemo(billOutBO.getRemark());//备注
            soMaster.setExpectTimeFm(billOutBO.getPlanStartDate());//计划开工日期
            soMaster.setCustomerId(billOutBO.getCustomerId());//客户ID
            soMaster.setCustomerName(billOutBO.getCustomerName());//客户名称
            //新增
            soMasters.add(soMaster);
            //详情
            List<SoDetail> soDetails = newDetail.stream().filter(item -> item.getErpBillId() == soMaster.getBeforeNum()).map(menu -> {
                menu.setBillNo(soMaster.getBillNo());
                return menu;
            }).collect(Collectors.toList());
            addDetail.addAll(soDetails);
        }
        soMasterService.saveBatch(soMasters);
        saveBatch(addDetail);

    }

    @Override
    public List<SoDetailDto> findUndistributedSoDetail(Integer soType) {
        return soDetailMapper.findUndistributedSoDetail(soType);
    }

    @Override
    public List<SoDetail> findByMasterId(Integer soId) {
        return soDetailMapper.findByMasterId(soId);
    }

    @Override
    public List<SoDayList> findDayList(SoDetailCriteria criteria) {
        return soDetailMapper.findDayList(criteria);
    }

    @Override
    public List<SoLogItemDto> findLogItemsByBillNos(List<String> billNos) {
        return soDetailMapper.findLogItemsByBillNos(billNos);
    }

    @Override
    public List<SoDetailDto> findDetailsByWaveId(Integer wareId, Integer waveId) {
        return soDetailMapper.findDetailsByWaveId(wareId, waveId);
    }

    /**
     * 查询借料项 全部项
     *
     * @param billNo
     * @return
     */
    @Override
    public SoDetailVo findAll(String billNo) {
        SoDetailVo soDetailVo = new SoDetailVo();
        List<SoDetail> soDetailList = list(new QueryWrapper<SoDetail>().eq("bill_no", billNo));
        if (ObjectUtil.isNotEmpty(soDetailList)) {
            soDetailVo.setAll(soDetailList); // 全部项
            soDetailVo.setLend(this.lendDetail(soDetailList));//借料项
        }
        return soDetailVo;
    }


    /**
     * @param inventoryList 库存余量表
     * @param itemCode      物料编码
     * @return
     */
    public Double putNumber(List<Inventory> inventoryList, String itemCode, Integer organizationId) {
        //入库数量-分配数量 -冻结数量   //货主id 88货主Id默认为 -1 自有, code SYS_MINE
        return inventoryList.stream().filter(item -> item.getItemCode().equals(itemCode) && item.getOrganizationId() == organizationId).mapToDouble(item ->
                item.getQuantity() - item.getAllotQuantity() - item.getFreezeQuantity()
        ).sum();
    }

    /**
     * 获取所有数据
     *
     * @param billNos@return
     */
    @Override
    public List<SoDetail> findByOrderNo(List<String> billNos) {
        return baseMapper.findByOrderNo(billNos);
    }

    /**
     * 过滤单号查询数据
     *
     * @param contrastVo@return
     */
    @Override
    public List<SoDetail> beBeing(ContrastVo contrastVo) {
        return baseMapper.beBeing(contrastVo);
    }

    @Override
    public Integer getStockId(String asnDetailNo) {
        String cellCode = baseMapper.findbyCellCode(asnDetailNo);
        return cellInfoService.findbyCellCode(cellCode);
    }

    @Override
    public SoDetail findOne(String waveCode, String itemCode, Double quantity) {
        return baseMapper.findOne(waveCode, itemCode, quantity);
    }

    @Override
    public Set<SoDetail> soList(String waveCode, String itemCode) {
        return baseMapper.soList(waveCode, itemCode);
    }


    @Autowired
    private CellInfoService cellInfoService;

    @Autowired
    private CrmDeptAreaService crmDeptAreaService;

    //获取供料项
    public List<SoDetail> lendDetail(List<SoDetail> list) {
        SoDetail soDetail = list.listIterator().next();
        SoMaster soMaster = soMasterService.getOne(new QueryWrapper<SoMaster>().eq("bill_no", soDetail.getBillNo()));
        List<Integer> areaIds = crmDeptAreaService.listByDeptId(soMaster.getDeptId());

        Set<String> itemCodes = list.stream().map(SoDetail::getItemCode).collect(Collectors.toSet());
        List<ItemInfo> itemInfos = itemInfoService.list(new QueryWrapper<ItemInfo>().in("item_code", itemCodes));
        Map<String, ItemInfo> itemMap = convertMap(itemInfos, ItemInfo::getItemCode);
        //查找库存
        List<Inventory> inventories = inventoryService.list(new QueryWrapper<Inventory>().in("item_code", itemCodes)
                .notIn("cell_code", 28500, 285333)
        );
        List<Integer> notAasnStock = pushErpService.getNotAasnStock();
        List<String> notCellCode = Arrays.asList("285000", "285333");
        inventories = inventories.stream().filter(item ->
                areaIds.contains(item.getErpAreaId())
                        //过滤直发虚仓，先发配件，VMI
                        && !notAasnStock.contains(item.getAsnStockId())
                        //过滤合格未入库，待检
                        && !notCellCode.contains(item.getCellCode())).collect(Collectors.toList());

        Map<String, List<Inventory>> invMap = inventories.stream().collect(Collectors.groupingBy(Inventory::getItemCode));
        List<SoDetail> collect = list.stream().filter(item -> item.getOrderQuantity() > item.getAllottedQuantity())
                .map(item -> {
                    ItemInfo itemInfo = itemMap.get(item.getItemCode());
                    item.setFeedCategory(Optional.ofNullable(itemInfo).map(menu -> menu.getFeedCategory()).orElse(""));
                    //库存数量
                    item.setTotalNum(ObjectUtil.isNotEmpty(invMap.get(item.getItemCode()))
                                    ? invMap.get(item.getItemCode()).stream().mapToDouble(menu -> {
                                return menu.getQuantity() - menu.getAllotQuantity();
                            }).sum()
                                    : 0.00
                    );
                    return item;
                })
                .collect(Collectors.toList());
        return collect.stream().filter(item -> item.getTotalNum() <= 0).collect(Collectors.toList());
    }


    @Override
    public void contrastSoDetail(List<SoDetail> allDetails, Map<SoDetail, SoDetail> newMap, Map<SoDetail, SoDetail> oldMap) {
        for (SoDetail key : allDetails) {
            SoDetail newSd = newMap.get(key);
            SoDetail oldSd = oldMap.get(key);
            if (newSd == null) {
                //如果已经复核，回传给ERP则不需要改变
                if (oldSd.getOrderQuantity() - oldSd.getPickQuantity() <= 0) {
                    continue;
                }
                List<PickTask> pickTasks = pickTaskService.list(new QueryWrapper<PickTask>().eq("so_detail_id", oldSd.getSoDetailId())
                        .eq("state", 0)
                );
                if (ObjectUtil.isNotEmpty(pickTasks)) {
                    PickTaskCriteria pickTaskCriteria = new PickTaskCriteria();
                    List<Integer> pickIds = pickTasks.stream().map(item -> item.getPickTaskId()).collect(Collectors.toList());
                    pickTaskCriteria.setIds(pickIds);
                    List<PickTask> list = pickTaskService.listByIds(pickIds);
                    for (PickTask pickTask : list) {
                        pickTask.setState(WareTaskConstant.PICK_STATE_CANCELED);
                        pickTaskService.updateById(pickTask);
                        Inventory inventory = inventoryService.getById(pickTask.getInventoryId());
                        if (ObjectUtil.isNotEmpty(inventory)) {
                            inventory.setAllotQuantity(inventory.getAllotQuantity() - pickTask.getPickQuantity());
                            inventoryService.updateById(inventory);
                        }
                        SoDetail soDetail = getById(pickTask.getSoDetailId());
                        WaveDetail waveDetail = waveDetailService.getById(pickTask.getWaveDetailId());
                        if (ObjectUtil.isNotEmpty(waveDetail)) {
                            waveDetail.setAllottedQuantity(waveDetail.getAllottedQuantity()-pickTask.getPickQuantity());
                            waveDetailService.updateById(waveDetail);
                        }
                        if (ObjectUtil.isEmpty(soDetail)) {
                            continue;
                        }
                        if (soDetail.getAllottedQuantity() < 0) {
                            soDetail.setAllottedQuantity(0.00);
                        } else {
                            soDetail.setAllottedQuantity(soDetail.getAllottedQuantity() - pickTask.getPickQuantity());
                        }
                        this.updateById(soDetail);
                    }
                }



                //如果老单子删除
                removeById(oldSd.getSoDetailId());
                WaveDetail waveDetail = waveDetailService.getById(oldSd.getWaveDetailId());
                if (ObjectUtil.isEmpty(waveDetail)) {
                    continue;
                }
                //已分配
                if (waveDetail.getQuantity() > oldSd.getOrderQuantity()) {
                    waveDetail.setQuantity(waveDetail.getQuantity() - oldSd.getOrderQuantity());
                    waveDetailService.updateById(waveDetail);
                } else {
                    waveDetailService.removeById(waveDetail);
                }
            } else if (ObjectUtil.isEmpty(oldSd)) {
                //如果老单子为空则新增一条
                newSd.setState(0);
                this.save(newSd);
                ;
            } else {
                //同步仓库
                oldSd.setStockId(newSd.getStockId());
                //都有，则判断数量，有变化则修改
                if (ObjectUtil.notEqual(oldSd.getOrderQuantity(), newSd.getOrderQuantity())) {
                    Double newQty = newSd.getOrderQuantity();
                    oldSd.setOrderQuantity(newQty);
                }
                this.updateById(oldSd);
            }
        }

    }

    /**
     * 生产退料
     *
     * @param billNo
     * @return
     */
    @Override
    public List<SoDetail> findReturnList(String billNo) {
        List<SoDetail> soDetails = list(new QueryWrapper<SoDetail>().eq("bill_no", billNo));
        List<SoDetail> soDetailList = soDetails.stream().filter(item -> item.getDeliveryQuantity() - item.getReturnQty() > 0).collect(Collectors.toList());
        for (SoDetail soDetail : soDetailList) {
            soDetail.setAllReturnQuantity(soDetail.getDeliveryQuantity() - soDetail.getReturnQty());
        }
        return soDetailList;
    }
}
